Appearance
[中文版本](/posts/c教程/zh-CN/08-调试测试与 profiling/071-Debugging with gdb)
Every C programmer eventually meets a segmentation fault, and that’s when you discover your most powerful companion: gdb, the GNU Debugger. Debugging isn’t about luck; it’s about learning to inspect a program as it runs, to pause time, and to see what the computer is really doing.
Let’s learn how to use gdb to find bugs, inspect memory, trace crashes, and truly understand your code.
Step 1. Compiling with Debug Information
Before you can debug, you need to tell the compiler to include symbol information (variable names, line numbers, etc.). Use the-g flag:
gcc -g main.c -o mainYou can now open it in gdb:
gdb ./mainStep 2. Starting and Running Your Program
Inside gdb, you can run your program just like normal:
(gdb) runIf it crashes, you’ll get something like:
Program received signal SIGSEGV, Segmentation fault.
0x000000000040114a in buggy_function () at main.c:12
12 *ptr = 42;You now know exactly where it failed.
Step 3. Setting Breakpoints
A breakpoint tells gdb to pause before executing a specific line or function.
(gdb) break main
Breakpoint 1 at 0x40113b: file main.c, line 5.
(gdb) runWhen the program stops, you can inspect state:
(gdb) print variable_name
(gdb) next
(gdb) stepnextexecutes the next line (skipping function calls).stepgoes into a function call.
Step 4. Example: A Simple Bug
Here’s a program with a classic segmentation fault.
#include <stdio.h>
void buggy(void) {
int *p = NULL;
*p = 10;
}
int main(void) {
printf("Before crash\n");
buggy();
printf("After crash\n");
}Compile and debug:
gcc -g bug.c -o bug
gdb ./bug
(gdb) runOutput:
Program received signal SIGSEGV, Segmentation fault.
0x0000555555555159 in buggy () at bug.c:5
5 *p = 10;Now inspect:
(gdb) backtrace
#0 buggy () at bug.c:5
#1 main () at bug.c:10You’ve just traced the crash from main to the exact faulty line.
Step 5. Inspecting Variables
You can view variable values anytime:
(gdb) print x
(gdb) print *ptrYou can also modify them:
(gdb) set variable x = 100To list all local variables:
(gdb) info localsStep 6. Navigating Execution
Common gdb commands:
| Command | Action |
|---|---|
run | Start the program |
break N | Stop at line N |
next | Run next line |
step | Step into function |
continue | Resume until next breakpoint |
finish | Run until function returns |
backtrace | Show call stack |
info locals | List local vars |
print VAR | Show value |
quit | Exit gdb |
Step 7. Watching Variables
You can set watchpoints, gdb stops when a variable changes.
int counter = 0;
for (int i = 0; i < 10; i++)
counter += i;In gdb:
(gdb) watch counter
(gdb) runEvery timecounter changes, the program pauses, showing where it happened.
Step 8. Conditional Breakpoints
Sometimes you only want to stop under specific conditions:
(gdb) break loop.c:25 if i > 100This breakpoint triggers only wheni exceeds 100.
Step 9. Inspecting Memory and Registers
You can inspect raw memory:
(gdb) x/10x &arrayThis prints 10 hexadecimal words starting at&array.
Or view registers:
(gdb) info registersThis is useful for low-level debugging (e.g., compilers, OS kernels, embedded code).
Step 10. Tiny Code: Debugging a Logic Bug
#include <stdio.h>
int main(void) {
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum = sum + i;
}
printf("Sum = %d\n", sum); // should be 15
}Introduce a bug:
for (int i = 1; i <= 5; i++); // extra semicolon!Compile and debug:
gcc -g bug.c -o bug
gdb ./bug
(gdb) break main
(gdb) run
(gdb) print sum
(gdb) next
(gdb) print sumYou’ll see thatsum never changes, because the loop body was empty.
Why It Matters
Debugging is how you learn to think like the machine:
- You can inspect what happens between lines.
- You can see every variable’s value.
- You can find segmentation faults in seconds.
Learning gdb teaches you how C really runs, from stack frames to pointers.
Try It Yourself
- Write a program that crashes (e.g., use a null pointer) and trace the cause with gdb.
- Use
nextandstepto trace a recursive function. - Set a watchpoint on a variable in a loop.
- Add a conditional breakpoint that triggers only when a value exceeds a limit.
- Explore
backtraceandinfo localsafter a crash.
Next, you’ll learn how to detect hidden memory errors, leaks, invalid frees, and buffer overflows, using the indispensable Valgrind tool.
